#include <iostream>
#include <string>
#include <cerrno>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
// #include <mutex>
// #include <condition_variable>
#include "nocopy.hpp"
#include "Log.hpp"
#include "comm.hpp"
#include "InetAddr.hpp"
#include "Threadpool.hpp"
const static uint16_t defaultport = 8888;
const static int defaultfd = -1;
const static int defaultsize = 1024;
using task_t = std::function<void ()>;

class UdpServer :public nocopy
{
public:
    UdpServer( uint16_t port = defaultport)
        :_port(port), _sockfd(defaultfd)
        {
            pthread_mutex_init(&_user_mutex, nullptr);
        }
    void Init()
    {
        // 1.创建socket， 就是创建了文件细节
        _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if(_sockfd < 0)
        {
            lg.LogMessage(Fatal, "socket err, %d : %s\n", errno, strerror(errno));
            exit(Socket_err);
        }

        lg.LogMessage(Info, "socket success, sockfd: %d\n", _sockfd);

        // 添加地址重用选项
        int opt = 1;
        setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

        // 2.绑定， 指定网络信息
        struct sockaddr_in local;
        bzero(&local, sizeof(local));  //将sockaddr_in local中的内容全部设定为0
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = INADDR_ANY; // 0
        // local.sin_addr.s_addr = htonl(INADDR_ANY);  // 修改这里，使用INADDR_ANY

        //  结构体填完， 设置到内核中了吗？？ 没有
        int n = ::bind(_sockfd, (struct sockaddr *)&local, sizeof(local));
        if(n != 0)
        {
            lg.LogMessage(Fatal, "bind err, %d : %s\n", errno, strerror(errno));
            exit(Bind_Err);
        }
        
        lg.LogMessage(Info, "bind success\n");  // 添加绑定成功的日志

        ThreadPool<task_t>::GetInstance()->Start();
    }
    
    void AddOnlineUser(InetAddr addr)
    {
        LockGuard lockguard(&_user_mutex);
        for(auto &user: _online_user)
        {
            if(addr == user)
            {
                return ;
            }
        }
        _online_user.push_back(addr);
        lg.LogMessage(Debug, "%s:%d is add to onlineuser list...\n", addr.IP().c_str(), addr.Port());
    }

    void Route(int sock, const std::string &message)
    {
        for(auto &user : _online_user)
        {
            sendto(sock, message.c_str(), message.size(), 0, (struct sockaddr*)&user.GetAddr(), sizeof(user.GetAddr()));
            lg.LogMessage(Debug, "server send message to %s:%d, message: %s", user.IP().c_str(), user.Port(), message.c_str());
        }
    }

    void Start()
    {
        char buffer[defaultsize];
        std::cout << "Server is running on port: " << _port << std::endl << std::flush;
        while(true)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            ssize_t n = recvfrom(_sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &len);
            if(n > 0)
            {

                InetAddr addr(peer);
                uint16_t clientport = ntohs(peer.sin_port);
                std::string clientip = inet_ntoa(peer.sin_addr);

                AddOnlineUser(addr);
                

                buffer[n] = 0;
                std::string message = "[";
                message += addr.IP();
                message += "=";
                message += std::to_string(addr.Port());
                message += "]#";
                message += buffer;
                std::cout << "[" << "clientinfo" << "]#" << buffer << std:: endl;
                std::cout << "client say#" << buffer << std::endl << std::flush;
                std::cout << "client addr: " << inet_ntoa(peer.sin_addr) << ":" << ntohs(peer.sin_port) << std::endl << std::flush;
                
                task_t task = std::bind(&UdpServer::Route, this, _sockfd, buffer);
                ThreadPool<task_t>::GetInstance()->Push(task);
            
                const char* response = "Message received!";
                // ssize_t s = sendto(_sockfd, response, strlen(response), 0, (struct sockaddr*)&peer, len);
                // if(s < 0)
                // {
                //     lg.LogMessage(Error, "sendto failed: %s\n", strerror(errno));
                //     perror("sendto");  // 添加更详细的错误信息
                // }
                // else
                // {
                //     std::cout << "Sent " << s << " bytes to client" << std::endl << std::flush;
                // }
            }
            else if(n < 0)
            {
                lg.LogMessage(Error, "recvfrom failed: %s\n", strerror(errno));
            }
        }
    }

    ~UdpServer()
    {
        pthread_mutex_destroy(&_user_mutex);
    }

private:
    std::string _ip;
    uint16_t _port;
    int _sockfd;
    std::vector<InetAddr> _online_user; //会被多个线程同时访问的
    pthread_mutex_t _user_mutex;
};

//sudo netstat -anup 查询